﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using DevComponents.AdvTree;
using System.Configuration;
using Common.Utils;
using Common.DataBase.Interface;
using Common.DataBase.Implement;
using System.Threading.Tasks;
using System.Security.AccessControl;
using System.Diagnostics;
using System.Threading;
using System.Data.SQLite;
using System.Data.Common;
using System.Collections;
using Common.DataBase;
using Common.IO;
using Bll;
using ScanFile.Model;
using DevComponents.DotNetBar.Controls;

namespace ScanFile {
  [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
  [ComVisible(true)]  
  public partial class FormMain : DevComponents.DotNetBar.Office2007Form {

    private log4net.ILog _logger = log4net.LogManager.GetLogger(typeof(FormMain));
    private FileExBll fileExBll = new FileExBll();
    private FolderExBll folderExBll = new FolderExBll();
    private CancellationTokenSource _tokenSource = new CancellationTokenSource();
    private CancellationToken _token;


    #region  系统API
    [DllImport("user32.dll", EntryPoint = "GetWindowThreadProcessId", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    private static extern long GetWindowThreadProcessId(long hWnd, long lpdwProcessId);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern long SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

    [DllImport("user32.dll", EntryPoint = "GetWindowLongA", SetLastError = true)]
    private static extern long GetWindowLong(IntPtr hwnd, int nIndex);

    [DllImport("user32.dll", EntryPoint = "SetWindowLongA", SetLastError = true)]
    private static extern long SetWindowLong(IntPtr hwnd, int nIndex, long dwNewLong);
    //private static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
    [DllImport("user32.dll", SetLastError = true)]
    private static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long x, long y, long cx, long cy, long wFlags);
    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool MoveWindow(IntPtr hwnd, int x, int y, int cx, int cy, bool repaint);
    [DllImport("user32.dll", EntryPoint = "PostMessageA", SetLastError = true)]
    private static extern bool PostMessage(IntPtr hwnd, uint Msg, long wParam, long lParam);
    private const int SWP_NOOWNERZORDER = 0x200;
    private const int SWP_NOREDRAW = 0x8;
    private const int SWP_NOZORDER = 0x4;
    private const int SWP_SHOWWINDOW = 0x0040;
    private const int WS_EX_MDICHILD = 0x40;
    private const int SWP_FRAMECHANGED = 0x20;
    private const int SWP_NOACTIVATE = 0x10;
    private const int SWP_ASYNCWINDOWPOS = 0x4000;
    private const int SWP_NOMOVE = 0x2;
    private const int SWP_NOSIZE = 0x1;
    private const int GWL_STYLE = (-16);
    private const int WS_VISIBLE = 0x10000000;
    private const int WM_CLOSE = 0x10;
    private const int WS_CHILD = 0x40000000;


    /// <summary>
    /// 最大化窗口，最小化窗口，正常大小窗口；
    /// </summary>
    [DllImport("user32.dll", EntryPoint = "ShowWindow", CharSet = CharSet.Auto)]
    public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);


    #endregion


    public FormMain() {
      InitializeComponent();
      System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;//跨线程访问控件 
      _token = _tokenSource.Token;
      this.Load += new EventHandler(FormMain_Load);
      this.FormClosing += FormMain_FormClosing;
      this.Resize += FormMain_Resize;
      this.displayName.BeforeCellPaint += fileName_BeforeCellPaint;
      this.displayName2.BeforeCellPaint += fileName2_BeforeCellPaint;
      dataGridViewXMain.RowPostPaint += DataGridViewXMain_RowPostPaint;
      dataGridViewXMain.CellContentClick += DataGridViewXMain_CellContentClick;
      dataGridViewXMain.CellContentDoubleClick += DataGridViewXMain_CellContentDoubleClick;
      advTreeComputer.SelectionChanged += AdvTreeComputer_SelectionChanged;
      dataGridViewXSameFile.CellContentClick += DataGridViewXSameFile_CellContentClick;//相同文件列表中的删除操作
    }

    private void DataGridViewXSameFile_CellContentClick(object sender, DataGridViewCellEventArgs e) {
      if (e.RowIndex > -1) {
        FileEx fileEx = dataGridViewXSameFile.Rows[e.RowIndex].Tag as FileEx;
        if (fileEx != null) {
          DataGridViewRow row = dataGridViewXSameFile.Rows[e.RowIndex];
          if (row.Cells[e.ColumnIndex].Value.ToString() == "删除") {
            try {
              File.Delete(fileEx.FullName);
              fileExBll.DeleteFileExByPathMd5(fileEx.PathMd5);              
              dataGridViewXSameFile.Rows.Remove(row);
              if (dataGridViewXMain.SelectedRows != null && dataGridViewXMain.SelectedRows.Count > 0) {
                DataGridViewRow mainGridRow = dataGridViewXMain.SelectedRows[0];
                FileEx mainData = mainGridRow.Tag as FileEx;
                if(mainData.SameFileCount > 1) {
                  mainData.SameFileCount = mainData.SameFileCount - 1;
                  if (mainData.SameFileCount > 1) {
                    mainGridRow.DefaultCellStyle.BackColor = Color.Yellow;
                  } else {
                    mainGridRow.DefaultCellStyle.BackColor = Color.White;
                  }
                }
                if (mainData.FullName == fileEx.FullName) {
                  dataGridViewXMain.Rows.Remove(mainGridRow);
                }
                dataGridViewXSameFile.Rows.Clear();
                DirectoryInfo directoryInfo = new DirectoryInfo(fileEx.FolderFullName);
                while (directoryInfo != null && directoryInfo.GetDirectories().Length <= 0 && directoryInfo.GetFiles().Length <= 0) {
                  DirectoryInfo parent = directoryInfo.Parent;
                  directoryInfo.Delete();
                  directoryInfo = parent;
                }
              }
              fileExBll.UpdateSameFileCount(fileEx);
            } catch (Exception exception) {
              _logger.Error(exception);
            }
          }
        }
      }
    }

    private void DataGridViewXMain_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e) {
      if (e.RowIndex > -1) {
        FolderEx folder = dataGridViewXMain.Rows[e.RowIndex].Tag as FolderEx;
        if (folder != null) {
          advTreeComputer.SelectedNode.Expand();
          foreach (Node treeNode in advTreeComputer.SelectedNode.Nodes) {
            DirectoryInfo directoryInfo = treeNode.Tag as DirectoryInfo;
            if (directoryInfo != null && directoryInfo.FullName == folder.FullName) {
              treeNode.Expand();
              advTreeComputer.SelectNode(treeNode, eTreeAction.Expand);
              break;
            }
          }
        }
      }
    }

    private void AdvTreeComputer_SelectionChanged(object sender, EventArgs e) {
      loadDataGridViewX();
    }

    private void DataGridViewXMain_CellContentClick(object sender, DataGridViewCellEventArgs e) {
      if (e.RowIndex > -1) {
        dataGridViewXSameFile.Rows.Clear();
        FileEx file = dataGridViewXMain.Rows[e.RowIndex].Tag as FileEx;
        if (file != null) {
          advPropertyGrid.SelectedObject = file;
          loadSameFileDataGridViewX(file.Md5);
        } else {
          FolderEx folder = dataGridViewXMain.Rows[e.RowIndex].Tag as FolderEx;
          if (folder != null) {
            advPropertyGrid.SelectedObject = folder;
          }
        }
      }
    }

    private void loadSameFileDataGridViewX(string fileMd5) {
      if (advTreeComputer.SelectedNode.Tag is DirectoryInfo) {
        try {
          List<FileEx> fileExList = fileExBll.GetListByMd5(fileMd5);
          if (fileExList != null && fileExList.Count > 0) {
            System.Reflection.PropertyInfo[] properties = fileExList[0].GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (FileEx file in fileExList) {
              int index = dataGridViewXSameFile.Rows.Add();
              DataGridViewRow row = dataGridViewXSameFile.Rows[index];
              foreach (System.Reflection.PropertyInfo item in properties) {
                string columName = string.Format("{0}2", item.Name.Trim('_'));
                if (dataGridViewXSameFile.Columns.Contains(columName)){
                  row.Cells[columName].Value = item.GetValue(file, null);
                }
              }
              row.Cells["btnDelete"].Value = "删除";
              row.Tag = file;
            }
          }
        } catch (Exception exception) {
          _logger.Error(exception);
        } finally {
          this.advTreeComputer.Enabled = true;
        }
      }
    }


    //最小化事件,显示到托盘  
    private void FormMain_Resize(object sender, EventArgs e) {
      if (this.WindowState == FormWindowState.Minimized) {
        this.Visible = false;
      }
    }

    private void fileName_BeforeCellPaint(object sender, BeforeCellPaintEventArgs e) {
      DataGridViewLabelXColumn fileNameColumn = sender as DataGridViewLabelXColumn;
      if (fileNameColumn != null) {
        if (!string.IsNullOrEmpty(fileNameColumn.Text) == true && this.dataGridViewXMain.Rows[e.RowIndex].Cells["fullName"].Value != null) {
          long imageIndex = -1;
          string path = Convert.ToString(this.dataGridViewXMain.Rows[e.RowIndex].Cells["fullName"].Value);
          if (dataGridViewXMain.Rows[e.RowIndex].Tag is FileEx) {
            fileNameColumn.Image = SystemIcon.GetFileIcon(path, true, out imageIndex).ToBitmap();
          } else {
            fileNameColumn.Image = SystemIcon.GetFolderIcon(path, true, out imageIndex).ToBitmap();
          }          
        }
      }
    }

    private void fileName2_BeforeCellPaint(object sender, BeforeCellPaintEventArgs e) {

      DataGridViewLabelXColumn fileNameColumn = sender as DataGridViewLabelXColumn;
      if (fileNameColumn != null) {
        if (!string.IsNullOrEmpty(fileNameColumn.Text) == true && this.dataGridViewXSameFile.Rows[e.RowIndex].Cells["fullName2"].Value != null) {
          long imageIndex = -1;
          string path = Convert.ToString(this.dataGridViewXSameFile.Rows[e.RowIndex].Cells["fullName2"].Value);
          if (dataGridViewXSameFile.Rows[e.RowIndex].Tag is FileEx) {
            fileNameColumn.Image = SystemIcon.GetFileIcon(path, true, out imageIndex).ToBitmap();
          } else {
            fileNameColumn.Image = SystemIcon.GetFolderIcon(path, true, out imageIndex).ToBitmap();
          }
        }
      }
    }

    private void DataGridViewXMain_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) {
      if (e.RowIndex > -1) {
        FileEx file = dataGridViewXMain.Rows[e.RowIndex].Tag as FileEx;
        if (file != null) {
          if (file.SameFileCount > 1) {
            this.dataGridViewXMain.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Yellow;
          }
        }
      }     
    }

    private void FormMain_FormClosing(object sender, FormClosingEventArgs e) {
      //if (MessageBox.Show("确定退出程序?","信息",MessageBoxButtons.OKCancel,MessageBoxIcon.Question) == DialogResult.OK) {
      //  _tokenSource.Cancel();        
      //} else {
      //  e.Cancel = true;
      //}
      _tokenSource.Cancel();
      //e.Cancel = true;
    }

    void FormMain_Load(object sender, EventArgs e) {
      advTreeComputer.NodeClick += AdvTreeComputer_NodeClick;
      advTreeComputer.NodeDoubleClick += AdvTreeComputer_NodeDoubleClick;
      advTreeComputer.BeforeExpand += AdvTreeComputer_BeforeExpand;
      treeNodeRightButtonMenue.Items.Add("扫描",Image.FromFile("./image/zoom.png"), ContextMenuItem_Click);
      treeNodeRightButtonMenue.Items.Add("删除",Image.FromFile("./image/delete.png"), ContextMenuItem_Click);
      treeNodeRightButtonMenue.Items.Add("打开文件夹", Image.FromFile("./image/folder_explore.png"), ContextMenuItem_Click);

      rootNodeRightButtonMenue.Items.Add("重复文件", Image.FromFile("./image/application_cascade.png"), rootNodeRightButtonMenueMenuItem_Click);

      LoodTreeRootNode();
    }

    private void rootNodeRightButtonMenueMenuItem_Click(object sender, EventArgs e) {
      ToolStripItem toolStripItem = sender as ToolStripItem;
      if (toolStripItem != null && toolStripItem.Text.Trim() == "重复文件") {
        Task task = new Task(() => {
          LoadSameFiles();
          CircularProgressForm.getInstance().Hide();
        });
        task.Start();
        CircularProgressForm.getInstance().ShowDialog(this);
      }
    }

    private void LoadSameFiles() {
      try {
        dataGridViewXMain.Rows.Clear();
        List<FileEx> fileExList = fileExBll.GetSameFiles();
        if (fileExList != null && fileExList.Count > 0) {
          System.Reflection.PropertyInfo[] properties = fileExList[0].GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
          foreach (FileEx file in fileExList) {
            if (File.Exists(file.FullName)) {
              int index = dataGridViewXMain.Rows.Add();
              DataGridViewRow row = dataGridViewXMain.Rows[index];
              foreach (System.Reflection.PropertyInfo item in properties) {
                if (dataGridViewXMain.Columns.Contains(item.Name.Trim('_'))) {
                  row.Cells[item.Name].Value = item.GetValue(file, null);
                }
              }
              row.Tag = file;
            } else {
              Task task = new Task(() => {
                if (!string.IsNullOrWhiteSpace(file.PathMd5)) {
                  fileExBll.DeleteFileExByPathMd5(file.PathMd5);
                }
              });
              task.Start();
            }
          }
        }
      } catch (Exception exception) {
        _logger.Error(exception);
      } finally {
        this.advTreeComputer.Enabled = true;
      }
    }

    private void ContextMenuItem_Click(object sender, EventArgs e) {
      ToolStripItem toolStripItem = sender as ToolStripItem;
      if (toolStripItem != null && toolStripItem.Text.Trim() == "扫描") {
        scanComputer();
      } else if (toolStripItem != null && toolStripItem.Text.Trim() == "删除") {        
        if (advTreeComputer.SelectedNode.Tag is DirectoryInfo || advTreeComputer.SelectedNode.Tag is FileInfo) {          
          Task task = new Task(() => {
            Thread.Sleep(200);
            if (advTreeComputer.SelectedNode.Tag is DirectoryInfo) {
              if (deleteFolder(advTreeComputer.SelectedNode.Tag as DirectoryInfo)) {
                if (advTreeComputer.SelectedNode.Parent != null) {
                  Node currentNode = advTreeComputer.SelectedNode;
                  advTreeComputer.SelectedNode = advTreeComputer.SelectedNode.Parent;
                  advTreeComputer.SelectedNode.Nodes.Remove(currentNode);
                }
              }
            } else if (advTreeComputer.SelectedNode.Tag is FileInfo) {
              FileInfo fileInfo = advTreeComputer.SelectedNode.Tag as FileInfo;
              if (fileInfo != null) {
                if (advTreeComputer.SelectedNode.Parent != null) {
                  fileInfo.Delete();
                  Node currentNode = advTreeComputer.SelectedNode;
                  advTreeComputer.SelectedNode = advTreeComputer.SelectedNode.Parent;
                  advTreeComputer.SelectedNode.Nodes.Remove(currentNode);
                }
              }
            }           
            CircularProgressForm.getInstance().Hide();
          });
          task.Start();
          CircularProgressForm.getInstance().ShowDialog(this);
        }
      } else if (toolStripItem != null && toolStripItem.Text.Trim() == "打开文件夹") {
        if (advTreeComputer.SelectedNode.Tag is DirectoryInfo) {
          DirectoryInfo directoryInfo = advTreeComputer.SelectedNode.Tag as DirectoryInfo;
          if (directoryInfo != null) {
            System.Diagnostics.Process.Start("explorer.exe", directoryInfo.FullName);
          }
        }
      }
    }




    private bool deleteFolder(DirectoryInfo directoryInfo) {
      bool result = false;
      if (directoryInfo != null && directoryInfo.FullName.Trim('\\').Trim(':') != directoryInfo.Root.FullName.Trim('\\').Trim(':')) {
        try {
          directoryInfo.Delete(true);
          fileExBll.DeleteOrphanFileEx(directoryInfo.FullName.Trim('\\'));
          folderExBll.DeleteOrphanFolderEx(directoryInfo.FullName.Trim('\\'));
          result = true;
        } catch (UnauthorizedAccessException ex) {
          _logger.Error(ex.Message, ex);
        } catch (Exception ex) {
          _logger.Error(ex.Message, ex);
        }
      }
      return result;
    }

    private void scanComputer() {
      DriveInfo[] allDirves = DriveInfo.GetDrives();
      foreach (DriveInfo item in allDirves) {
        try {
          if (item.DriveType == DriveType.CDRom || item.DriveType == DriveType.Unknown || item.Name.Trim('\\').Trim(':') == "C") {
            continue;
          }
          Task task = new Task(() => scanFileByDirctoryInfo(new DirectoryInfo(item.Name)), _token);
          task.Start();
        } catch (Exception ex) {
          _logger.Error(ex.Message, ex);
        }
      }
    }


    private FileEx GenerateFileEx(FileInfo file,string diskLabel = null, string diskNumber=null) {
      _logger.Debug(file.FullName);
      FileEx fileEx = new FileEx();
      try {
        System.Security.AccessControl.FileSecurity fileSecurity = file.GetAccessControl();
        if (fileSecurity.AreAccessRulesProtected) {
          fileSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
          fileSecurity.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
          file.SetAccessControl(fileSecurity);
        }        
        if (string.IsNullOrWhiteSpace(diskLabel)) {
          fileEx.DiskLabel = file.Directory.Root.Name.Trim('\\').Trim(':');
        } else {
          fileEx.DiskLabel = diskLabel.Trim('\\').Trim(':');
        }
        if (string.IsNullOrWhiteSpace(diskNumber)) {
          fileEx.DiskNumber = Common.Utils.DiskDriver.GetHardDiskNumberByVolume(fileEx.DiskLabel);
        } else {
          fileEx.DiskNumber = diskNumber;
        }
        string dateTimeNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        fileEx.Extension = file.Extension;
        fileEx.FullName = file.FullName;
        fileEx.FileName = file.Name;
        fileEx.FileSize = file.Length;
        fileEx.FolderFullName = file.Directory.FullName;
        fileEx.CreationTime = file.CreationTime.ToString("yyyy-MM-dd HH:mm:ss");
        fileEx.LastAccessTime = file.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss");
        fileEx.LastWriteTime = file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
        fileEx.Md5 = Common.Utils.MD5Util.GetMD5HashFromFile(file.FullName);
        fileEx.PathMd5 = Common.Utils.MD5Util.CreateMD5Hash(file.FullName);
        fileEx.FolderMd5 = Common.Utils.MD5Util.CreateMD5Hash(file.Directory.FullName.Trim('\\'));
        fileEx.RecordTime = dateTimeNow;
        fileEx.ScanTime = dateTimeNow;
      } catch (System.IO.PathTooLongException pathTooLongException) {
        _logger.Error(string.Format("获取文件信息失败,已跳过此文件：{0}", file.FullName));
        _logger.Error(pathTooLongException.Message, pathTooLongException);
        return null;
      } catch (System.UnauthorizedAccessException unauthorizedAccessException) {
        _logger.Error(string.Format("获取文件信息失败,已跳过此文件：{0}", file.FullName));
        _logger.Error(unauthorizedAccessException.Message, unauthorizedAccessException);
        return null;
      } catch (Exception ex) {
        _logger.Error(string.Format("收集文件信息失败：{0}", file.LastWriteTime));
        _logger.Error(string.Format("收集文件信息失败：{0}", file.FullName));
        _logger.Error(ex.Message, ex);
        return null;
      }
      return fileEx;
    }

    private FileEx CopyFileEx(FileEx srcFileEx, FileEx destFileEx) {
      if (srcFileEx != null && destFileEx != null) {
        destFileEx.FileSize = srcFileEx.FileSize;
        destFileEx.LastAccessTime = srcFileEx.LastAccessTime;
        destFileEx.LastWriteTime = srcFileEx.LastWriteTime;
        destFileEx.FolderMd5 = srcFileEx.FolderMd5;
        destFileEx.PathMd5 = srcFileEx.PathMd5;
        destFileEx.Md5 = srcFileEx.Md5;
        destFileEx.ScanTime = srcFileEx.ScanTime;
      }      
      return destFileEx;
    }

    private FolderEx GenerateFolderEx(DirectoryInfo directoryInfo, string diskLabel = null, string diskNumber = null) {
      _logger.Debug(directoryInfo.FullName);
      FolderEx folderEx = new FolderEx();
      try {
        System.Security.AccessControl.DirectorySecurity folderSecurity = directoryInfo.GetAccessControl();
        if (folderSecurity.AreAccessRulesProtected) {
          folderSecurity.AddAccessRule(new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, AccessControlType.Allow));
          folderSecurity.AddAccessRule(new FileSystemAccessRule("Users", FileSystemRights.FullControl, AccessControlType.Allow));
          directoryInfo.SetAccessControl(folderSecurity);
        }
        if (string.IsNullOrWhiteSpace(diskLabel)) {
          folderEx.DiskLabel = directoryInfo.Root.Name.Trim('\\').Trim(':');
        } else {
          folderEx.DiskLabel = diskLabel.Trim('\\').Trim(':');
        }
        if (string.IsNullOrWhiteSpace(diskNumber)) {
          folderEx.DiskNumber = Common.Utils.DiskDriver.GetHardDiskNumberByVolume(folderEx.DiskLabel);
        } else {
          folderEx.DiskNumber = diskNumber;
        }
        string dateTimeNow = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        folderEx.FileCount = directoryInfo.GetFiles().Length;
        folderEx.SubfolderCount = directoryInfo.GetDirectories().Length;
        folderEx.FolderFullName = directoryInfo.FullName;
        folderEx.FolderName = directoryInfo.Name;
        folderEx.LastAccessTime = directoryInfo.LastAccessTime.ToString("yyyy-MM-dd HH:mm:ss");
        folderEx.LastWriteTime = directoryInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss");
        folderEx.RecordTime = dateTimeNow;
        folderEx.ScanTime = dateTimeNow;
        folderEx.Id = Common.Utils.MD5Util.CreateMD5Hash(folderEx.FolderFullName);
        if (directoryInfo.Root == null || directoryInfo.FullName.Trim('\\') == directoryInfo.Root.FullName.Trim('\\')) {
          folderEx.Parent = string.Empty;
        } else {
          folderEx.Parent = Common.Utils.MD5Util.CreateMD5Hash(directoryInfo.Parent.FullName.Trim('\\').Trim(':'));
        }
      } catch (Exception ex) {
        _logger.Error(ex.Message, ex);
      }   
      return folderEx;
    }

    private FolderEx CopyFolderEx(FolderEx srcFolder, FolderEx destFolder) {
      if (srcFolder != null && destFolder != null) {
        destFolder.LastAccessTime = srcFolder.LastAccessTime;
        destFolder.LastWriteTime = srcFolder.LastWriteTime;
        destFolder.ScanTime = srcFolder.ScanTime;
        destFolder.SubfolderCount = srcFolder.SubfolderCount;
        destFolder.FolderFullName = srcFolder.FolderFullName;
        destFolder.FolderName = srcFolder.FolderName;
        destFolder.FileCount = srcFolder.FileCount;
      }
      return destFolder;
    }
    
    public void scanFileByDirctoryInfo(DirectoryInfo directoryInfo, string diskLabel = null, string diskNumber = null) {
      _logger.Debug(directoryInfo.FullName);
      //if (directoryInfo.FullName.Trim('\\') == Application.StartupPath.Trim('\\')) {
      //  return;
      //}
      DirectorySecurity directorySecurity = new DirectorySecurity(directoryInfo.FullName, AccessControlSections.Access);
      //判断目录是否 可以访问  
      //if (!directorySecurity.AreAccessRulesProtected)
      {
        if (string.IsNullOrWhiteSpace(diskLabel)) {
          diskLabel = directoryInfo.Root.Name.Trim('\\').Trim(':');
        }
        if (string.IsNullOrWhiteSpace(diskNumber)) {
          diskNumber = Common.Utils.DiskDriver.GetHardDiskNumberByVolume(diskLabel);
        }
        if (directoryInfo != null && directoryInfo is DirectoryInfo) {
          try {
            FolderEx folder = folderExBll.GetFolderExByPrimary(Common.Utils.MD5Util.CreateMD5Hash(directoryInfo.FullName));
            if (folder == null || folder.LastWriteTime != directoryInfo.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")) {
              FileInfo[] files = directoryInfo.GetFiles();
              List<FileEx> fileList = new List<FileEx>();
              foreach (FileInfo file in files) {
                FileEx fileEx = fileExBll.GetFileExByPathMd5(Common.Utils.MD5Util.CreateMD5Hash(file.FullName));
                if (fileEx == null) {
                  fileEx = GenerateFileEx(file, diskLabel, diskNumber);
                  if (fileEx != null) {
                    fileExBll.Add(fileEx);
                  }                  
                } else {
                  if (file.LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss") != fileEx.LastWriteTime || file.Length != fileEx.FileSize) {
                    FileEx newFileEx = GenerateFileEx(file, diskLabel, diskNumber);
                    if (newFileEx != null) {
                      fileEx = CopyFileEx(newFileEx, fileEx);
                      fileExBll.UpdateEntity(fileEx);
                    }                   
                  }
                }
                if (fileEx != null) {
                  //fileExBll.UpdateSameFileCount(fileEx);
                }                
              }
              try {
                fileExBll.InsertList(fileList);
              } catch (Exception exception) {
                _logger.Error(exception);
              }
              if (folder == null) {
                folderExBll.InsertOne(GenerateFolderEx(directoryInfo, diskLabel, diskNumber));
              } else {
                folderExBll.UpdateEntity(CopyFolderEx(GenerateFolderEx(directoryInfo, diskLabel, diskNumber), folder));
              }
            }

            DirectoryInfo[] directorys = directoryInfo.GetDirectories();
            foreach (DirectoryInfo childDirectory in directorys) {
              if ((childDirectory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) {// || (directoryInfo.Attributes & FileAttributes.System) == FileAttributes.System) {//为隐藏的文件夹
                continue;
              }
              directorySecurity = new DirectorySecurity(childDirectory.FullName, AccessControlSections.Access);
              //判断目录是否 可以访问  
              if (!directorySecurity.AreAccessRulesProtected) {
                try {
                  scanFileByDirctoryInfo(childDirectory, diskLabel, diskNumber);
                } catch (Exception exception) {
                  _logger.Error(exception);
                }
              }
            }
          } catch (AggregateException exceptions) {
            foreach (Exception exception in exceptions.InnerExceptions) {
              _logger.Error(exception);
            }
          }
        }
      }
    }
    

    ContextMenuStrip treeNodeRightButtonMenue = new ContextMenuStrip();
    ContextMenuStrip rootNodeRightButtonMenue = new ContextMenuStrip();
    private void AdvTreeComputer_NodeClick(object sender, TreeNodeMouseEventArgs e) {
      if (e.Button == MouseButtons.Right) {
        DirectoryInfo directoryInfo = advTreeComputer.SelectedNode.Tag as DirectoryInfo;
        if (directoryInfo != null && directoryInfo.Root.FullName != directoryInfo.FullName) {
          treeNodeRightButtonMenue.Items[0].Visible = true;
          treeNodeRightButtonMenue.Items[1].Visible = true;
          treeNodeRightButtonMenue.Items[2].Visible = true;
          treeNodeRightButtonMenue.Show(advTreeComputer, new Point(e.X, e.Y));//鼠标右键按下弹出菜单
        } else if (directoryInfo != null) {
          treeNodeRightButtonMenue.Items[0].Visible = true;
          treeNodeRightButtonMenue.Items[1].Visible = false;
          treeNodeRightButtonMenue.Items[2].Visible = true;
          treeNodeRightButtonMenue.Show(advTreeComputer, new Point(e.X, e.Y));
        } else {
          FileInfo fileInfo = advTreeComputer.SelectedNode.Tag as FileInfo;
          if (fileInfo != null) {
            treeNodeRightButtonMenue.Items[0].Visible = false;
            treeNodeRightButtonMenue.Items[1].Visible = true;
            treeNodeRightButtonMenue.Items[2].Visible = false;
            treeNodeRightButtonMenue.Show(advTreeComputer, new Point(e.X, e.Y));
          } else {
            treeNodeRightButtonMenue.Items[0].Visible = false;
            treeNodeRightButtonMenue.Items[1].Visible = true;
            treeNodeRightButtonMenue.Items[2].Visible = false;
            rootNodeRightButtonMenue.Show(advTreeComputer, new Point(e.X, e.Y));
          }            
        }
      }
    }

    IntPtr appWin = IntPtr.Zero;
    private void AdvTreeComputer_NodeDoubleClick(object sender, TreeNodeMouseEventArgs e) {      
      if (e.Button == MouseButtons.Left) {       
        if (advTreeComputer.SelectedNode.Tag is FileInfo) {
          Process process = new Process();
          process.StartInfo.FileName = advTreeComputer.SelectedNode.Tooltip;
          process.Start();
          process.WaitForInputIdle();
          ShowWindow(process.MainWindowHandle,3);
        }
      } 
    }


    private void loadDataGridViewX() {
      if (advTreeComputer.SelectedNode.Tag is DirectoryInfo) {
        try {
          this.advTreeComputer.Enabled = false;
          DirectoryInfo directoryInfo = advTreeComputer.SelectedNode.Tag as DirectoryInfo;
          List<FolderEx> folderExList = folderExBll.GetListByParentFolder(Common.Utils.MD5Util.CreateMD5Hash(directoryInfo.FullName.Trim('\\').Trim(':')));
          dataGridViewXMain.Rows.Clear();
          if (folderExList != null && folderExList.Count > 0) {
            System.Reflection.PropertyInfo[] properties = folderExList[0].GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (FolderEx folder in folderExList) {
              if (Directory.Exists(folder.FolderFullName)) {
                int index = dataGridViewXMain.Rows.Add();
                DataGridViewRow row = dataGridViewXMain.Rows[index];
                foreach (System.Reflection.PropertyInfo item in properties) {
                  if (dataGridViewXMain.Columns.Contains(item.Name.Trim('_'))) {
                    row.Cells[item.Name].Value = item.GetValue(folder, null);
                  }
                }
                row.Tag = folder;
              } else {
                Task task = new Task(() => {
                  folderExBll.DeleteFolderEx(folder.Id);
                });
                task.Start();
              }
            }
          }
          List<FileEx> fileExList = fileExBll.GetListByParentFolder(Common.Utils.MD5Util.CreateMD5Hash(directoryInfo.FullName.Trim('\\').Trim(':')));
          if (fileExList != null && fileExList.Count > 0) {
            System.Reflection.PropertyInfo[] properties = fileExList[0].GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
            foreach (FileEx file in fileExList) {
              if (File.Exists(file.FullName)) {
                int index = dataGridViewXMain.Rows.Add();
                DataGridViewRow row = dataGridViewXMain.Rows[index];
                foreach (System.Reflection.PropertyInfo item in properties) {
                  if (dataGridViewXMain.Columns.Contains(item.Name.Trim('_'))) {
                    row.Cells[item.Name].Value = item.GetValue(file, null);
                  }
                }
                row.Tag = file;
              } else {
                Task task = new Task(() => {
                  if (!string.IsNullOrWhiteSpace(file.PathMd5)) {
                    fileExBll.DeleteFileExByPathMd5(file.PathMd5);
                  }                  
                });
                task.Start();
              }
            }
          }
        } catch (Exception exception) {
          _logger.Error(exception);
        } finally {
          this.advTreeComputer.Enabled = true;
        }
      }
    }

    private void AdvTreeComputer_BeforeExpand(object sender, AdvTreeNodeCancelEventArgs e) {
      try {
        e.Node.Nodes.Clear();
        if (e.Node.Tooltip == "我的电脑") {
          LoodTreeRootNode();
        } else {
          InitailChildrenNodes(e.Node, 1);
        }        
      } catch (Exception exception) {
        _logger.Error(exception);
      }
    }


    private void LoodTreeRootNode() {
      Node rootNode = null;
      if (advTreeComputer.Nodes.Count > 0) {
        if (advTreeComputer.Nodes[0].Text == "我的电脑") {
          rootNode = advTreeComputer.Nodes[0];
        } else {
          advTreeComputer.Nodes.Clear();
        }
      }
      if (rootNode == null) {
        rootNode = new Node();
        rootNode.Text = "我的电脑";
        rootNode.Tooltip = "我的电脑";
        rootNode.Tag = null;
        rootNode.CheckBoxVisible = false;
        rootNode.CheckBoxThreeState = rootNode.CheckBoxVisible;
        rootNode.Checked = false;
        rootNode.Image = Image.FromFile(@"image\house.png");
        advTreeComputer.Nodes.Add(rootNode);
      }
      try {
        DriveInfo[] allDirves = DriveInfo.GetDrives();
        List<Node> driverNodes = new List<Node>();
        foreach (DriveInfo item in allDirves) {
          try {

            if (item.DriveType == DriveType.CDRom || item.DriveType == DriveType.Unknown) {
              continue;
            }
            Node driverNode = new Node();
            string volumeLabel = item.VolumeLabel;
            string volumeName = item.Name.Trim('\\');

            if (item.DriveType == DriveType.Fixed) {
              driverNode.Tooltip = "硬盘";
              if (string.IsNullOrEmpty(volumeLabel)) {
                volumeLabel = "本地磁盘";
              }
            } else if (item.DriveType == DriveType.Removable) {
              driverNode.Tooltip = "可移动磁盘";
              if (string.IsNullOrEmpty(volumeLabel)) {
                volumeLabel = "可移动磁盘";
              }
            }

            if (string.IsNullOrEmpty(volumeLabel)) {
              driverNode.Text = volumeName;
            } else {
              driverNode.Text = string.Format("{0}({1})", volumeLabel, volumeName);
            }
            driverNode.Tooltip = driverNode.Tooltip + string.Format("\r\n容量：{0}，可用空间大小：{1}", DiskDriver.GetSpaceSize(item.TotalSize), DiskDriver.GetSpaceSize(item.TotalFreeSpace));
            driverNode.Tag = new DirectoryInfo(item.Name);
            driverNode.CheckBoxVisible = rootNode.CheckBoxVisible;
            driverNode.CheckBoxThreeState = rootNode.CheckBoxThreeState;
            driverNode.Checked = rootNode.Checked;
            driverNode.Image = SystemIcon.GetDriverIcon(item.Name[0], true).ToBitmap();
            bool exists = false;
            foreach (Node driver in rootNode.Nodes) {
              if (driver.Text == driverNode.Text) {
                exists = true;
                break;
              }
            }
            if (exists == false) {
              rootNode.Nodes.Add(driverNode);
              Task task = new Task(() => InitailChildrenNodes(driverNode), _token);
              task.Start();
            }
          } catch (Exception ex) {
            _logger.Error(ex.Message, ex);
          }
        }
      } catch (Exception ex) {
        _logger.Error(ex.Message, ex);
      }
      rootNode.Expand();      
    }


    private void InitailChildrenNodes(Node parentNode, int deep = 1) {
      if (deep > 2) {
        return;
      }
      if (parentNode.Tag is DirectoryInfo) {
        DirectoryInfo directory = parentNode.Tag as DirectoryInfo;
        try {
          parentNode.Nodes.Clear();
          DirectoryInfo[] directorys = directory.GetDirectories();
          foreach (DirectoryInfo childDirectory in directorys) {
            if ((childDirectory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden || (childDirectory.Attributes & FileAttributes.System) == FileAttributes.System) {//系统和隐藏的文件夹
              continue;
            }
            DirectorySecurity directorySecurity = new DirectorySecurity(childDirectory.FullName, AccessControlSections.Access);
            //判断目录是否 可以访问  
            Node folderNode = new Node();
            folderNode.Text = childDirectory.Name;
            folderNode.Tooltip = childDirectory.FullName;
            long imageIndex = -1;
            folderNode.Image = SystemIcon.GetFolderIcon(childDirectory.FullName, true, out imageIndex).ToBitmap();
            folderNode.CheckBoxVisible = parentNode.CheckBoxVisible;
            folderNode.CheckBoxThreeState = parentNode.CheckBoxThreeState;
            folderNode.Checked = parentNode.Checked;
            folderNode.Tag = childDirectory;
            if (!directorySecurity.AreAccessRulesProtected) {
              try {
                if (childDirectory.FullName != AppDomain.CurrentDomain.SetupInformation.ApplicationBase) {
                  Task task = new Task(() => InitailChildrenNodes(folderNode,deep+1), _token);
                  task.Start();
                }
              } catch (Exception exception) {
                _logger.Error(exception);
              }
            } else {
              folderNode.Tooltip += "\r\n没有权限访问此文件夹。";
            }            
            parentNode.Nodes.Add(folderNode);
            if (deep == 2) {
              return;
            }
          }
          FileInfo[] files = directory.GetFiles();
          foreach (FileInfo file in files) {
            try {
              Node fileNode = new Node();
              fileNode.Text = file.Name;
              fileNode.Tooltip = file.FullName;
              long imageIndex = -1;
              fileNode.Image = SystemIcon.GetFileIcon(file.FullName, true, out imageIndex).ToBitmap();
              fileNode.CheckBoxVisible = parentNode.CheckBoxVisible;
              fileNode.CheckBoxThreeState = parentNode.CheckBoxThreeState;
              fileNode.Checked = parentNode.Checked;
              fileNode.Tag = file;
              parentNode.Nodes.Add(fileNode);
            } catch (Exception exception) {
              _logger.Error(exception);
            }
          }
        } catch (AggregateException exceptions) {
          foreach (Exception exception in exceptions.InnerExceptions) {
            _logger.Error(exception);
          }         
        }
      }
    }
    

    protected override void WndProc(ref Message winMessage) {
      if (winMessage.Msg == CWndProMsgConst.WM_DEVICECHANGE) {
        LoodTreeRootNode();
      }
      base.WndProc(ref winMessage);
    }

    //托盘图标单击显示  
    private void notifyIcon_MouseClick(object sender, MouseEventArgs e) {
      //this.contextMenuStrip.Show();
    }

    private void FormWindowStateMax_Click(object sender, EventArgs e) {
      if (this.WindowState == FormWindowState.Minimized) {
        this.Visible = true;
        this.TopMost = true;
        this.WindowState = FormWindowState.Maximized;
      }
      this.Activate();
    }

    private void FormWindowStateClose_Click(object sender, EventArgs e) {
      Application.Exit();
    }

    private void notifyIcon_DoubleClick(object sender, EventArgs e) {
      if (this.WindowState == FormWindowState.Minimized) {
        this.Visible = true;
        //this.TopMost = true;
        this.WindowState = FormWindowState.Maximized;
      }      
      this.Activate();
    }

    private void dataGridViewXMain_MouseClick(object sender, MouseEventArgs e) {
      
    }
  }

  class CWndProMsgConst {
    public const int WM_DEVICECHANGE = 0x219; // 系统硬件改变发出的系统消息
    public const int DBT_DEVICEARRIVAL = 0x8000;// 设备检测结束，并且可以使用
    public const int DBT_CONFIGCHANGECANCELED = 0x0019;
    public const int DBT_CONFIGCHANGED = 0x0018;
    public const int DBT_CUSTOMEVENT = 0x8006;
    public const int DBT_DEVICEQUERYREMOVE = 0x8001;
    public const int DBT_DEVICEQUERYREMOVEFAILED = 0x8002;
    public const int DBT_DEVICEREMOVECOMPLETE = 0x8004;// 设备卸载或者拔出
    public const int DBT_DEVICEREMOVEPENDING = 0x8003;
    public const int DBT_DEVICETYPEHANGED = 0x0007;
    public const int DBT_QUERYCHANGSPECIFIC = 0x8005;
    public const int DBT_DEVNODES_CECONFIG = 0x0017;
    public const int DBT_USERDEFINED = 0xFFFF;
  }
}
